package org.dut.community.config;

import org.dut.community.util.CommunityConstant;
import org.dut.community.util.CommunityUtil;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.security.web.context.SecurityContextRepository;

@Configuration
public class SecurityConfig implements CommunityConstant {

    // 忽略静态资源
    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -> web.ignoring().requestMatchers("/resources/**");
    }

    // 配置安全策略
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        // 请求授权
        http.authorizeHttpRequests(authorize -> authorize.requestMatchers(
                                "/user/setting",  // 用户设置
                                "/user/upload",   // 上传头像
                                "/user/updatePassword",  // 修改密码
                                "/discuss/add",   // 上传帖子
                                "/comment/add/**", // 评论
                                "/letter/**",     // 私信
                                "/notice/**",    // 通知
                                "/like",         // 点赞
                                "/follow",       // 关注
                                "/unfollow"      // 取消关注
                                ,"/discuss/delete" // 删除帖子(作者，管理员，版主可删除)
                        ).hasAnyAuthority(
                                AUTHORITY_ADMIN,
                                AUTHORITY_MODERATOR,
                                AUTHORITY_USER
                        ).requestMatchers(
                                "/discuss/top",
                                "/discuss/wonderful"
                        ).hasAnyAuthority(
                                AUTHORITY_MODERATOR
                        ).requestMatchers(
                                "/data/**",
                                "/actuator/**"
                        ).hasAnyAuthority(
                                AUTHORITY_ADMIN
                        ).
                        anyRequest().permitAll()

        );

       // 权限不够时的处理方式 普通请求返回登录页面，异步请求返回报错信息（Json）
        http.exceptionHandling(handler ->handler.authenticationEntryPoint(
                // 未登录时的处理方式
                ((request, response, authException) -> {
                    String xRequestedWith = request.getHeader("x-requested-With");
                    // 异步请求
                    if ("XMLHttpRequest".equals(xRequestedWith)) {
                        response.setContentType("application/plain;charset=UTF-8");
                        response.getWriter().write(CommunityUtil.getJSONString(403,"您还没有登录"));
                    }else {
                        response.sendRedirect(request.getContextPath() + "/login");
                    }
                })
        ).accessDeniedHandler(((request, response, accessDeniedException) -> {
            // 已登录但权限不够
            String xRequestedWith = request.getHeader("x-requested-With");
            if ("XMLHttpRequest".equals(xRequestedWith)) {
                response.setContentType("application/plain;charset=UTF-8");
                response.getWriter().write(CommunityUtil.getJSONString(403,"您没有权限访问"));
            }else {
                response.sendRedirect(request.getContextPath() + "/login");
            }
        })
        ));

        // logout 登出 ,修改Spring Security 拦截logout的路径
        // 避免与原本logout功能的冲突
        http.logout(logout -> logout.logoutUrl("/securityLogout"));

        return http.build();
    }

    // 将安全信息存在session中
    @Bean
    public SecurityContextRepository securityContextRepository() {
        return new HttpSessionSecurityContextRepository();
    }

    // 登出时，清除所有的安全信息
    @Bean
    public SecurityContextLogoutHandler securityContextLogoutHandler() {
        return new SecurityContextLogoutHandler();
    }

}
